﻿#include "gamearea.h"

GameArea::GameArea(QWidget *parent) : QWidget(parent)
{
    this->setFixedSize(Col*Width,Row*Height);
    inData();
}

void GameArea::paintEvent(QPaintEvent *e)
{
    Q_UNUSED(e);
    QPainter painter(this);
    if(showGameArea)
    {
        for(int i=0;i<Row;++i)
            for(int j=0;j<Col;++j)
            {
                if(!(*isEmpty)[i][j])
                painter.drawPixmap(j*Width,i*Height,Width,Height,
                                   QPixmap(QString(":/image/%1.png").arg(PixmapData[i][j])));
            }
    }
}

void GameArea::newGame()
{
    showGameArea=true;
    update();
}

void GameArea::inData()
{
    showGameArea=false;
    QVector<int>*hasExist=new QVector<int>(Row/2*Col,0);
    for(int i=0;i<Row/2;++i)
        for(int j=0;j<Col;++j){
            int type=QRandomGenerator::global()->generate()%10;
            PixmapData[i][j]=type;
            while(true)
            {
                int tempIndex=QRandomGenerator::global()->generate()%(Row/2*Col)+ Row/2*Col;
                if((*hasExist)[tempIndex-Row/2*Col]==0)
                {
                    PixmapData[tempIndex/Row][tempIndex%Row]=type;

                    (*hasExist)[tempIndex-Row/2*Col]=1;
                    break;
                }
            }
        }
    isEmpty=new QVector<QVector<bool>>(Row,QVector<bool>(Col,false));
    clickCount=0;
    firstClickX=-1;
    firstClickY=-1;
}

bool GameArea::isWin()
{
    for(int i=0;i<Row;++i)
        for(int j=0;j<Col;++j)
        {
            if(!(*isEmpty)[i][j])
                return false;
        }
    return true;
}
void GameArea::mousePressEvent(QMouseEvent *e)
{
    int currentX=e->x()/Width;
    int currentY=e->y()/Height;
    if((*isEmpty)[currentY][currentX])
        return ;
    ++clickCount;
    if(clickCount%2!=0)
    {
        firstClickX=currentX;
        firstClickY=currentY;
    }

    else if(clickCount%2==0)
    {

        if(PixmapData[firstClickY][firstClickX]!=PixmapData[currentY][currentX]||
                (currentY==firstClickY&&currentX==firstClickX))
            return ;
        bool flag=canBeLinked(firstClickY,firstClickX,currentY,currentX);
        if(flag)
        {
            (*isEmpty)[firstClickY][firstClickX]=true;
            (*isEmpty)[currentY][currentX]=true;
            update();
        }


    }

}

void GameArea::mouseReleaseEvent(QMouseEvent *e)
{
    Q_UNUSED(e);
    emit updateProgress();
    bool youWin=isWin();
    if(youWin)
    {
        emit hasWin();
        if(QMessageBox::Ok==QMessageBox::question(this,"你赢了！","重开吗？",
                                                  QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel))
        {
            emit restart();
        }
        else{
            emit winCancel();
        }
    }
}

int GameArea::getProgress()
{
    double done=0;
    for(int i=0;i<Row;++i)
        for(int j=0;j<Col;++j)
        {
            if((*isEmpty)[i][j])
                done++;
        }
    return static_cast<int>(done/Row/Col*100);
}

bool GameArea::canBeLinked(int row1, int col1, int row2, int col2)
{
   return inOneLine(row1, col1, row2, col2)||inTwoLine(row1, col1, row2, col2)||inThreeLine(row1, col1, row2, col2);
}

bool GameArea::inOneLine(int row1, int col1, int row2, int col2)
{
    bool flag=true;
    if(row1==row2)
    {
        for(int i=qMin(col1,col2)+1;i<qMax(col1,col2);++i){
            if(!(*isEmpty)[row1][i])
            {
                flag=false;
                break;
            }
        }
        if(flag)
            return true;
    }
    else if(col1==col2)
    {
        for(int i=qMin(row1,row2)+1;i<qMax(row1,row2);i++)
        {
            if(!(*isEmpty)[i][col1])
            {
                return false;
            }
        }

        return true;
    }
    return false;
}

bool GameArea::inTwoLine(int row1, int col1, int row2, int col2)
{
    bool flag1=inOneLine(row1,col1,row1,col2)&&inOneLine(row1,col2,row2,col2);
    bool flag2=inOneLine(row1,col1,row2,col1)&&inOneLine(row2,col1,row2,col2);

    return ( flag1 && (*isEmpty)[row1][col2] ) || ( flag2 && (*isEmpty)[row2][col1] );

}
bool GameArea::inThreeLine(int row1, int col1, int row2, int col2)
{
    bool flag=false;
    for(int i=0;i<Col;i++)
    {
        if(i==col1)
            continue;

        if((*isEmpty)[row1][i]){
            flag=inOneLine(row1,i,row1,col1)&&inTwoLine(row1,i,row2,col2);
        }
        if(flag)
            return true;
    }
    for(int i=0;i<Row;i++)
    {
        if(i==row1)
            continue;

        if((*isEmpty)[i][col1]){
            flag=inOneLine(i,col1,row1,col1)&&inTwoLine(i,col1,row2,col2);
        }
        if(flag)
            return true;
    }
    return false;
}
